package com.xyt.imei.core.api;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.SortDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.luminary.common.framework.core.auth.ValidateToken;
import com.luminary.common.framework.core.exception.SysException;
import com.luminary.common.framework.core.model.Pagination;
import com.luminary.common.framework.core.model.SimpleResponse;
import com.luminary.component.util.common.BeanMapUtils;
import com.luminary.component.util.common.ExcelUtil;
import com.xyt.imei.core.meta.PageConstants;
import com.xyt.imei.core.meta.RoleEnum;
import com.xyt.imei.core.meta.StoreStatusEnum;
import com.xyt.imei.core.meta.TaskDetailStatusEnum;
import com.xyt.imei.core.meta.TraceEventEnum;
import com.xyt.imei.core.meta.ValidateConstants;
import com.xyt.imei.core.model.dto.BatchStoreDTO;
import com.xyt.imei.core.model.dto.StoreDTO;
import com.xyt.imei.core.model.dto.StoreQueryDTO;
import com.xyt.imei.core.model.po.Store;
import com.xyt.imei.core.model.po.Trace;
import com.xyt.imei.core.model.po.User;
import com.xyt.imei.core.model.vo.StoreVO;
import com.xyt.imei.core.service.StoreService;
import com.xyt.imei.core.util.TokenUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequestMapping("store")
public class StoreApi {

	@Autowired
	private TokenUtil tokenUtil;
	
	@Autowired
	private StoreService storeService;
	
	@ValidateToken(roles = {RoleEnum.ADMIN_VALUE + "", RoleEnum.CMCC_VALUE + "", RoleEnum.BRANCH_VALUE + ""})
	@GetMapping("/imeiNo/{imeiNo:[0-9]{15}}")
	public SimpleResponse query(
			@PathVariable String imeiNo,
			HttpServletResponse response) throws Exception {
		log.info("imeiNo:"+imeiNo);
		return SimpleResponse.success(storeService.findByImeiNo(imeiNo), response);
	}
	
	@ValidateToken(roles = {RoleEnum.ADMIN_VALUE + "", RoleEnum.BRANCH_VALUE + ""})
	@GetMapping("/page/{branchId}")
	public SimpleResponse query(
			@PathVariable("branchId") int branchId,
			@Valid StoreQueryDTO storeQueryDTO,
			@PageableDefault(page=PageConstants.DEFAULT_PAGE_NO,size=PageConstants.DEFAULT_PAGE_SIZE)
			@SortDefault.SortDefaults({
				@SortDefault(sort = "imei_no", direction = Direction.ASC),
				@SortDefault(sort = "create_date", direction = Direction.DESC)
			}) Pageable pageable,
			HttpServletResponse response) throws Exception {
		
		log.info("branchId:" + branchId + ",storeQueryDTO:"+storeQueryDTO.toString() + ",pageable:" + pageable.toString());
		
		Pagination<Store> pagination = new Pagination<Store>(pageable);
		
		Map<String, Object> params = new HashMap<String, Object>();
		params = BeanMapUtils.beanToMap(storeQueryDTO);
		params.put("userId", branchId);
		pagination.setParams(params, pageable);
		
		return SimpleResponse.success(storeService.findPageBybranch(pagination), response);
		
	}
	
	@ValidateToken(roles = {RoleEnum.ADMIN_VALUE + "", RoleEnum.BRANCH_VALUE + ""})
	@GetMapping("/self/page")
	public SimpleResponse query(
			@Valid StoreQueryDTO storeQueryDTO,
			@PageableDefault(page=PageConstants.DEFAULT_PAGE_NO,size=PageConstants.DEFAULT_PAGE_SIZE)
			@SortDefault.SortDefaults({
				@SortDefault(sort = "imei_no", direction = Direction.ASC),
				@SortDefault(sort = "create_date", direction = Direction.DESC)
			}) Pageable pageable,
			HttpServletResponse response) throws Exception {
		
		log.info("storeQueryDTO:"+storeQueryDTO.toString() + ",pageable:" + pageable.toString());
		
		User user = tokenUtil.getUser();
		
		Pagination<Store> pagination = new Pagination<Store>(pageable);
		
		Map<String, Object> params = new HashMap<String, Object>();
		params = BeanMapUtils.beanToMap(storeQueryDTO);
		params.put("userId", user.getUserId());
		pagination.setParams(params, pageable);
		
		return SimpleResponse.success(storeService.findPageBybranch(pagination), response);
		
	}
	
	@ValidateToken(roles = {RoleEnum.ADMIN_VALUE + "", RoleEnum.CMCC_VALUE + "",})
	@PostMapping
	public SimpleResponse store(
			@Valid StoreDTO storeDTO,
			HttpServletResponse response) throws Exception {
		
		log.info(storeDTO.toString());
		
		User user = tokenUtil.getUser();

		Store store = new Store();
		BeanUtils.copyProperties(storeDTO, store);
		store.setStatus(StoreStatusEnum.NORMAL.getValue());
		store.setCreateBy(user.getUserId());
		store.setCreateDate(new Date());
		
		if(storeService.store(store, user)) {
			return SimpleResponse.success("入库成功", response);
		} else {
			return SimpleResponse.failed("入库失败", response);
		}
		
	}
	
	/**
	 * 
	 * 性能不足可使用多线程版本
	 * 
	 * @param userid
	 * @param batchStoreDTO
	 * @param response
	 * @return
	 * @throws Exception
	 */
	/*@ValidateToken(roles = {RoleEnum.ADMIN_VALUE + "", RoleEnum.CMCC_VALUE + "",})
	@PostMapping("/batch/{userid}")
	public SimpleResponse store(
			@PathVariable("userid") int userid,
			@RequestBody @Valid List<BatchStoreDTO> batchStoreDTO,
			HttpServletResponse response) throws Exception {
		
		log.info("batch store");
		
		User user = tokenUtil.getUser();
		
		StringBuffer errorImeiNo = new StringBuffer();
		StringBuffer existsImeiNo = new StringBuffer();
		boolean hasFailure = false;
		
		List<Store> store = new ArrayList<Store>();
		List<Trace> trace = new ArrayList<Trace>();
		
		long startTime = System.currentTimeMillis();
		
		for(BatchStoreDTO batchStore : batchStoreDTO) {
			Store s = new Store();
			String imeiNo = batchStore.getImeiNo();
			if(StringUtils.isEmpty(imeiNo)) {
				continue;
			}
			if(!imeiNo.matches(ValidateConstants.REGEXP_IMEI)) {
				errorImeiNo.append(imeiNo+"\r\n");
				hasFailure = true;
			}  else {
				StoreVO vo = storeService.findByImeiNo(imeiNo);
				if(vo != null) {
					existsImeiNo.append(imeiNo+"\r\n");
					continue;
				}
				s.setImeiNo(batchStore.getImeiNo());
				s.setUserId(userid);
				s.setStatus(StoreStatusEnum.NORMAL.getValue());
				s.setCreateBy(user.getUserId());
				s.setCreateDate(new Date());
				store.add(s);
			}
		}

		store = removeDuplicate(store);
		for(Store s : store) {
			Trace t = new Trace();
			t.setImeiNo(s.getImeiNo());
			t.setEvent(TraceEventEnum.STORE.getValue());
			t.setSourceUserId(user.getUserId());
			t.setTargetUserId(userid);
			t.setCreateBy(user.getUserId());
			t.setCreateDate(new Date());
			trace.add(t);
		}
		
		log.info("took:"+(System.currentTimeMillis() - startTime)+"ms");
		
		if(store.size() == 0)  {
			if(hasFailure) {
				String content = "入库失败" +
						(StringUtils.isEmpty(errorImeiNo.toString()) ? "" : "\r\n存在不合法的串号:\r\n" + errorImeiNo.toString()) +
						(StringUtils.isEmpty(existsImeiNo.toString()) ? "" : "\r\n存在已存在的串号:\r\n" + existsImeiNo.toString());
				return SimpleResponse.failed(content, response);
			}
			else {
				String content = "入库失败" +
						(StringUtils.isEmpty(errorImeiNo.toString()) ? "" : "\r\n存在不合法的串号:\r\n" + errorImeiNo.toString()) +
						(StringUtils.isEmpty(existsImeiNo.toString()) ? "" : "\r\n存在已存在的串号:\r\n" + existsImeiNo.toString());
				return SimpleResponse.failed(content, response);
			}
		}
		
		if(storeService.store(store, trace, user)) {
			if(hasFailure) {
				String content = "入库成功" +
						(StringUtils.isEmpty(errorImeiNo.toString()) ? "" : "\r\n存在不合法的串号:\r\n" + errorImeiNo.toString()) +
						(StringUtils.isEmpty(existsImeiNo.toString()) ? "" : "\r\n存在已存在的串号:\r\n" + existsImeiNo.toString());
				return SimpleResponse.success(content, response);
			}
			else {
				String content = "入库成功" +
						(StringUtils.isEmpty(errorImeiNo.toString()) ? "" : "\r\n存在不合法的串号:\r\n" + errorImeiNo.toString()) +
						(StringUtils.isEmpty(existsImeiNo.toString()) ? "" : "\r\n存在已存在的串号:\r\n" + existsImeiNo.toString());
				return SimpleResponse.success(content, response);
			}
		} else {
			String content = "入库失败" +
					(StringUtils.isEmpty(errorImeiNo.toString()) ? "" : "\r\n存在不合法的串号:\r\n" + errorImeiNo.toString()) +
					(StringUtils.isEmpty(existsImeiNo.toString()) ? "" : "\r\n存在已存在的串号:\r\n" + existsImeiNo.toString());
			return SimpleResponse.failed(content, response);
		}
		
	}*/
	
	/**
	 * 
	 * 多线程版本，目前为2核2线程cpu，速度可提升1倍
	 * 
	 * @param list
	 * @return
	 */
	@ValidateToken(roles = {RoleEnum.ADMIN_VALUE + "", RoleEnum.CMCC_VALUE + "", RoleEnum.BRANCH_VALUE + ""})
	@PostMapping("/batch/{userid}")
	public SimpleResponse store(
			@PathVariable("userid") int userid,
			@RequestBody @Valid List<BatchStoreDTO> batchStoreDTO,
			HttpServletResponse response) throws Exception {
		
		log.info("batch store");
		
		User user = tokenUtil.getUser();
		
		CountDownLatch countDownLatch = new CountDownLatch(4);
		
		StringBuffer errorImeiNo = new StringBuffer();
		StringBuffer existsImeiNo = new StringBuffer();
		boolean hasFailure = false;
		
		final List<Store> store = new ArrayList<Store>();
		List<Trace> trace = new ArrayList<Trace>();
		
		int count = batchStoreDTO.size();
		List<BatchStoreDTO> ba = batchStoreDTO.subList(0, count/4);
		List<BatchStoreDTO> bb = batchStoreDTO.subList(count/4, count/4*2);
		List<BatchStoreDTO> bc = batchStoreDTO.subList(count/4*2, count/4*3);
		List<BatchStoreDTO> bd = batchStoreDTO.subList(count/4*3, count);
		Map<Integer, List<BatchStoreDTO>> map = new HashMap<Integer, List<BatchStoreDTO>>();
		map.put(1, ba);
		map.put(2, bb);
		map.put(3, bc);
		map.put(4, bd);
		
		Object lock = new Object();
		
		long startTime = System.currentTimeMillis();
		
		ExecutorService executor = Executors.newCachedThreadPool();
		
		for(int i = 0; i < 4; i++) {
			
			List<BatchStoreDTO> batchStoreList = map.get(i+1);
			
			executor.execute(new Runnable() {
				
				@Override
				public void run() {
					for(BatchStoreDTO batchStore : batchStoreList) {
						Store s = new Store();
						String imeiNo = batchStore.getImeiNo();
						if(StringUtils.isEmpty(imeiNo)) {
							continue;
						}
						if(!imeiNo.matches(ValidateConstants.REGEXP_IMEI)) {
							errorImeiNo.append(imeiNo+"\r\n");
							boolean hasFailure = true;
						}  else {
							StoreVO vo;
							try {
								vo = storeService.findByImeiNo(imeiNo);
							} catch (Exception e) {
								throw new SysException("500", "入库失败");
							}
							if(vo != null) {
								existsImeiNo.append(imeiNo+"\r\n");
								continue;
							}
							s.setImeiNo(batchStore.getImeiNo());
							s.setUserId(userid);
							s.setStatus(StoreStatusEnum.NORMAL.getValue());
							s.setCreateBy(user.getUserId());
							s.setCreateDate(new Date());
							synchronized (lock) {
								store.add(s);
							}
						}
					}
					countDownLatch.countDown();
				}
				
			});
		}
		
		countDownLatch.await();

		List<Store> storeList = removeDuplicate(store);
		for(Store s : storeList) {
			Trace t = new Trace();
			t.setImeiNo(s.getImeiNo());
			t.setEvent(TraceEventEnum.STORE.getValue());
			t.setSourceUserId(user.getUserId());
			t.setTargetUserId(userid);
			t.setCreateBy(user.getUserId());
			t.setCreateDate(new Date());
			trace.add(t);
		}
		
		log.info("took:"+(System.currentTimeMillis() - startTime)+"ms");
		
		if(storeList.size() == 0)  {
			if(hasFailure) {
				String content = "入库失败" +
						(StringUtils.isEmpty(errorImeiNo.toString()) ? "" : "\r\n存在不合法的串号:\r\n" + errorImeiNo.toString()) +
						(StringUtils.isEmpty(existsImeiNo.toString()) ? "" : "\r\n存在已存在的串号:\r\n" + existsImeiNo.toString());
				return SimpleResponse.failed(content, response);
			}
			else {
				String content = "入库失败" +
						(StringUtils.isEmpty(errorImeiNo.toString()) ? "" : "\r\n存在不合法的串号:\r\n" + errorImeiNo.toString()) +
						(StringUtils.isEmpty(existsImeiNo.toString()) ? "" : "\r\n存在已存在的串号:\r\n" + existsImeiNo.toString());
				return SimpleResponse.failed(content, response);
			}
		}
		
		if(storeService.store(storeList, trace, user)) {
			if(hasFailure) {
				String content = "入库成功" +
						(StringUtils.isEmpty(errorImeiNo.toString()) ? "" : "\r\n存在不合法的串号:\r\n" + errorImeiNo.toString()) +
						(StringUtils.isEmpty(existsImeiNo.toString()) ? "" : "\r\n存在已存在的串号:\r\n" + existsImeiNo.toString());
				return SimpleResponse.success(content, response);
			}
			else {
				String content = "入库成功" +
						(StringUtils.isEmpty(errorImeiNo.toString()) ? "" : "\r\n存在不合法的串号:\r\n" + errorImeiNo.toString()) +
						(StringUtils.isEmpty(existsImeiNo.toString()) ? "" : "\r\n存在已存在的串号:\r\n" + existsImeiNo.toString());
				return SimpleResponse.success(content, response);
			}
		} else {
			String content = "入库失败" +
					(StringUtils.isEmpty(errorImeiNo.toString()) ? "" : "\r\n存在不合法的串号:\r\n" + errorImeiNo.toString()) +
					(StringUtils.isEmpty(existsImeiNo.toString()) ? "" : "\r\n存在已存在的串号:\r\n" + existsImeiNo.toString());
			return SimpleResponse.failed(content, response);
		}
		
	}
	
	@GetMapping("/all")
	@ResponseBody
	public void listAll(
			@RequestParam("token") String token,
			HttpServletResponse response) throws Exception {
		
		log.info("list all");
		
		User user = tokenUtil.getUser(token);
		if(user == null)
			return;
		
		if(user.getRole() != 1 && user.getRole() != 2)
			return;
		
		Workbook workbook = storeService.export();
		response.reset();
		response.setHeader("Set-Cookie", "fileDownload=true; path=/");
		if(workbook == null)
			return;
		
		response.setContentType("application/vnd.ms-excel");
		String fileName = "串号" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
		response.setHeader("Content-disposition","attachment; filename="+new String(fileName.getBytes("gb2312"),"ISO-8859-1")+".xls");
		ServletOutputStream outStream=null;
		try{
		   outStream = response.getOutputStream();
		   workbook.write(outStream);
		}finally{
		   outStream.close();
		}
		
	}
	
	public List<Store> removeDuplicate(List<Store> list) {   
		List<Store> listTemp = new ArrayList<Store>();  
		List<String> imeiNoList = new ArrayList<String>(); 
        for(int i = 0; i < list.size(); i++){  
            if(!imeiNoList.contains(list.get(i).getImeiNo())){  
            	imeiNoList.add(list.get(i).getImeiNo());
                listTemp.add(list.get(i));  
            }  
        }  
        return listTemp;  
	}   
	
}
